//
//  CTFrameParser.m
//  TangQiao
//
//  Created by 宜必鑫科技 on 2017/10/13.
//  Copyright © 2017年 宜必鑫科技. All rights reserved.
//
/*
 @{
 NSFontAttributeName; //字体，value是UIFont对象
 NSParagraphStyleAttributeName;//绘图的风格（居中，换行模式，间距等诸多风格），value是NSParagraphStyle对象
 NSForegroundColorAttributeName;// 文字颜色，value是UIFont对象
 NSBackgroundColorAttributeName;// 背景色，value是UIFont
 NSLigatureAttributeName; //  字符连体，value是NSNumber
 NSKernAttributeName; // 字符间隔
 NSStrikethroughStyleAttributeName;//删除线，value是NSNumber
 NSUnderlineStyleAttributeName;//下划线，value是NSNumber
 NSStrokeColorAttributeName; //描绘边颜色，value是UIColor
 NSStrokeWidthAttributeName; //描边宽度，value是NSNumber
 NSShadowAttributeName; //阴影，value是NSShadow对象
 NSTextEffectAttributeName; //文字效果，value是NSString
 NSAttachmentAttributeName;//附属，value是NSTextAttachment 对象
 NSLinkAttributeName;//链接，value是NSURL or NSString
 NSBaselineOffsetAttributeName;//基础偏移量，value是NSNumber对象
 NSUnderlineColorAttributeName;//下划线颜色，value是UIColor对象
 NSStrikethroughColorAttributeName;//删除线颜色，value是UIColor
 NSObliquenessAttributeName; //字体倾斜
 NSExpansionAttributeName; //字体扁平化
 NSVerticalGlyphFormAttributeName;//垂直或者水平，value是 NSNumber，0表示水平，1垂直
 }
 */

#import "CTFrameParser.h"
#import "CoreTextImageData.h"
#import "CoreTextLinkData.h"

@implementation CTFrameParser


/* 直接控制全部的文字 */
+(CoreTextData *)parseContent:(NSString *)content config:(CTFrameParserConfig *)config{
    
    NSDictionary *attributes = [self attributesWithConfig:config];
    NSAttributedString *contextString = [[NSAttributedString alloc] initWithString:content attributes:attributes];
    
    //创建CTFrameStterRef实例
    CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)contextString);
    
    //获得要绘制的区域的高度
    CGSize restrictSize = CGSizeMake(config.width, CGFLOAT_MAX);
    CGSize coreTextSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, CFRangeMake(0, 0), nil, restrictSize, nil);
    CGFloat textHeight = coreTextSize.height;
    
    //生成CTFrameRef实例
    CTFrameRef frame = [self createFrameWithFramesetter:framesetter config:config height:textHeight];
    
    //将生成好的CTFrameRef实例和计算好的绘制高度保存到CoreTextData实例中，最后返回CoreTextData实例
    CoreTextData *data = [[CoreTextData alloc] init];
    data.ctFrameRef = frame;
    data.height = textHeight;
    
    //释放内存
    CFRelease(framesetter);
    CFRelease(frame);
    
    return data;
}


/* 下面两个方法表示的是可以控制AttributedString 来控制那些字变色 以及字体大小状态等等 */
// NSAttributedString  -->  CTFramesetterRef -->  CTFrameRef 直接生成 CoreTextData
+ (CoreTextData *)parseAttributedContent:(NSAttributedString *)content config:(CTFrameParserConfig *)config
{
    // 创建CTFramestetterRef实例 CTFramesetter是CTFrame对象的对象工厂。
    CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)content);
    
    // 根据文字得到绘制的高度
    CGSize restricitSize = CGSizeMake(config.width, CGFLOAT_MAX);
    CGSize coreTextSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, CFRangeMake(0, 0), nil, restricitSize, nil);
    CGFloat textHeight = coreTextSize.height;
    
    CTFrameRef frame = [self createFrameWithFramesetter:framesetter config:config height:textHeight];
    CoreTextData *coreTextData = [[CoreTextData alloc]init];
    coreTextData.ctFrameRef = frame;
    coreTextData.height = textHeight;
    
    CFRelease(frame);
    CFRelease(framesetter);
    return coreTextData;    
}

+ (CTFrameRef)createFrameWithFramesetter:(CTFramesetterRef)framesetter config:(CTFrameParserConfig*)config height:(CGFloat)hetght
{
    CGMutablePathRef path = CGPathCreateMutable();
    CGPathAddRect(path, NULL, CGRectMake(0, 0, config.width, hetght));
    CTFrameRef frameRef = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), path, NULL);
    CFRelease(path);
    return frameRef;
}

//（__bridge为OC对象和CF对象之间的桥接）
+ (NSDictionary *)attributesWithConfig:(CTFrameParserConfig *)config
{
    CGFloat fontSize = config.fontSize;
    CGFloat lineSpace = config.lineSpace;
    
    CTFontRef fontRef = CTFontCreateWithName((CFStringRef)@"ArialMT", fontSize, NULL);
    const CFIndex kNumberofSetting = 3;
    CTParagraphStyleSetting theSettings[kNumberofSetting] = {
        {kCTParagraphStyleSpecifierLineSpacingAdjustment,sizeof(CGFloat),& lineSpace},
        {kCTParagraphStyleSpecifierMaximumLineSpacing,sizeof(CGFloat), &lineSpace},
        {kCTParagraphStyleSpecifierMinimumLineSpacing,sizeof(CGFloat),&lineSpace}
    };
    CTParagraphStyleRef theParagraphRef = CTParagraphStyleCreate(theSettings, kNumberofSetting);
    
    UIColor *textColor = config.textColor;
    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    dict[(id)kCTForegroundColorAttributeName] = (id)textColor.CGColor;
    dict[(id)kCTFontAttributeName] = (__bridge id)fontRef;
    dict[(id)kCTParagraphStyleAttributeName] = (__bridge id)theParagraphRef;

    CFRelease(theParagraphRef);
    CFRetain(fontRef);
    return dict;
}





/* 下面的方法表示有JSON来控制显示的状态 */
+ (CoreTextData *)parseTemplateFile:(NSString *)path config:(CTFrameParserConfig *)config
{
    NSMutableArray *imageArray = [NSMutableArray array];
    NSMutableArray *linkArray  = [NSMutableArray array];
    NSAttributedString *content = [self loadTemplateFile:path config:config imageArray:imageArray linkArray:linkArray];
    CoreTextData *data = [self parseAttributedContent:content config:config];
    data.imageArray = imageArray;
    data.linkArray = linkArray;
    return data;
}

+(NSAttributedString *)loadTemplateFile:(NSString *)path config:(CTFrameParserConfig *)config
                             imageArray:(NSMutableArray *)imageArray
                              linkArray:(NSMutableArray *)linkArray
{
    NSData *data = [NSData dataWithContentsOfFile:path];
    NSMutableAttributedString *result = [[NSMutableAttributedString alloc]init];
    if (data)
    {
        NSArray *array = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
        if ([array isKindOfClass:[NSArray class]])
        {
            for (NSDictionary *dic in array)
            {
                NSString *type = dic[@"type"];
                if ([type isEqualToString:@"txt"])
                {
                    NSAttributedString *as = [self parseAttributedContentFromNSDictionary:dic config:config];
                    [result appendAttributedString:as];
                }
                else if ([type isEqualToString:@"img"])
                {
                    CoreTextImageData *data = [[CoreTextImageData alloc]init];
                    data.name = dic[@"name"];
                    data.position = [result length];
                    [imageArray addObject:data];
                    
                    /* 问题是生成的NSAttributedString的大小怎么计算？ 添加设置CTRunDelegate信息的方法*/
                    NSAttributedString *as = [self parseImageDataFromNSDictionary:dic config:config];
                    [result appendAttributedString:as];
                }
                else if ([type isEqualToString:@"link"]){
                    
                    NSUInteger startPos = result.length;
                    NSAttributedString *as = [self parseAttributedContentFromNSDictionary:dic config:config];
                    [result appendAttributedString:as];
                    
                    //创建CoreTextLinkData
                    NSUInteger length = result.length - startPos;
                    NSRange linkRange = NSMakeRange(startPos, length);
                    CoreTextLinkData *linkData = [[CoreTextLinkData alloc] init];
                    linkData.title = dic[@"content"];
                    linkData.url   = dic[@"url"];
                    linkData.range = linkRange;
                    [linkArray addObject:linkData];
                }
            }
        }
    }
    return result;
}

#pragma mark - 这个方法表示方法是生成文字内容所需要的方法
+ (NSAttributedString *)parseAttributedContentFromNSDictionary:(NSDictionary *)dict config:(CTFrameParserConfig *)config
{
    NSMutableDictionary *attributes = [NSMutableDictionary dictionaryWithDictionary:[self attributesWithConfig:config]];

    //设置颜色
    UIColor *color = [self colorFromTemplate:dict[@"color"]];
    if (color) {
        attributes[(id)kCTForegroundColorAttributeName] = (id)color.CGColor;
    }

    //设置字号
    CGFloat fontSize = [dict[@"size"] floatValue];
    if (fontSize>0) {
        CTFontRef fontRef = CTFontCreateWithName((CFStringRef)@"ArialMT", fontSize, NULL);
        attributes[(id)kCTFontAttributeName] = (__bridge id)fontRef;
        CFRelease(fontRef);
    }

    NSString *content = dict[@"content"];
    return [[NSAttributedString alloc] initWithString:content attributes:attributes];
}

//方法四：提供将NSString转换为UIColor的功能
+(UIColor *)colorFromTemplate:(NSString *)name
{
    if ([name isEqualToString:@"blue"]) {
        return [UIColor blueColor];
    }else if ([name isEqualToString:@"red"]){
        return [UIColor redColor];
    }else if ([name isEqualToString:@"black"]){
        return [UIColor blackColor];
    }else{
        return [UIColor greenColor];
    }
}






#pragma mark - 添加设置CTRunDelegate信息的方法
static CGFloat ascentCallback(void *ref)
{
    return [(NSNumber *)[(__bridge NSDictionary *)ref objectForKey:@"height"] floatValue];
}
static CGFloat descentCallback(void *ref)
{
    return 0;
}
static CGFloat widthCallback(void *ref)
{    
    return [(NSNumber *)[(__bridge NSDictionary *)ref objectForKey:@"width"] floatValue];
}

#pragma mark - 生成空白图片的占位符，并且设置他的CTRunDelegate信息  差不多就是一个字他的大小
+(NSAttributedString *)parseImageDataFromNSDictionary:(NSDictionary *)dict config:(CTFrameParserConfig *)config
{
    CTRunDelegateCallbacks callbacks;
    memset(&callbacks, 0, sizeof(CTRunDelegateCallbacks));
    callbacks.version = kCTRunDelegateVersion1;
    callbacks.getAscent = ascentCallback;
    callbacks.getDescent = descentCallback;
    callbacks.getWidth = widthCallback;
    CTRunDelegateRef delegate = CTRunDelegateCreate(&callbacks, (__bridge void *)dict);
    
    //使用0xFFFC作为空白占位符
    unichar objectReplacementChar = 0xFFFC;
    NSString *content = [NSString stringWithCharacters:&objectReplacementChar length:1];
    NSDictionary *attributes = [self attributesWithConfig:config];
    NSMutableAttributedString *space = [[NSMutableAttributedString alloc] initWithString:content attributes:attributes];
    CFAttributedStringSetAttribute((CFMutableAttributedStringRef)space, CFRangeMake(0, 1), kCTRunDelegateAttributeName, delegate);
    CFRelease(delegate);
    return space;
}


















@end











